home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / fsmake / disklabel.c < prev    next >
C/C++ Source or Header  |  1992-11-04  |  18KB  |  624 lines

  1. /* 
  2.  * disklabel.c --
  3.  *
  4.  *    Contains routines for modifying a disk's label..
  5.  *
  6.  * Copyright 1990 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/admin/fsmake/RCS/disklabel.c,v 1.2 90/10/10 16:00:33 rab Exp Locker: shirriff $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include "fsmake.h"
  21.  
  22. /*
  23.  * The 8 partitions, a through h.
  24.  */
  25. #define    A_PART    0
  26. #define B_PART    1
  27. #define C_PART    2
  28. #define D_PART    3
  29. #define E_PART    4
  30. #define F_PART    5
  31. #define G_PART    6
  32. #define H_PART    7
  33.  
  34. static ReturnStatus ScanDisktab();
  35.  
  36.  
  37. /*
  38.  *----------------------------------------------------------------------
  39.  *
  40.  * Reconfig --
  41.  *
  42.  *    Changes the configuration information of the disk. In
  43.  *    particular, the number of heads, sectors per track, and
  44.  *    cylinders may be changed.  If the "disktab" parameter is
  45.  *    true then the information is read from the disktab file.
  46.  *    Otherwise the disk is probed for its size and a
  47.  *    configuration is created that minimizes the amount of
  48.  *    wasted disk space.
  49.  *
  50.  * Results:
  51.  *    SUCCESS if the label was changed properly, FAILURE otherwise
  52.  *
  53.  * Side effects:
  54.  *    The disk configuration info in the label may be changed.
  55.  *    If it is changed then the partition map is zeroed.
  56.  *
  57.  *----------------------------------------------------------------------
  58.  */
  59.  
  60. ReturnStatus
  61. Reconfig(fid, disktab, disktabName, diskType, labelType, scsiDisk, labelPtrPtr)
  62.     int            fid;        /* Handle for first partition of disk*/
  63.     Boolean        disktab;    /* TRUE => use disktab file. */
  64.     char        *disktabName;    /* Name of disktab file. */
  65.     char        *diskType;    /* Type of disk. */
  66.     Disk_NativeLabelType labelType;    /* Type of label to write. */
  67.     int            scsiDisk;    /* TRUE => it's a scsi disk. */
  68.     Disk_Label        **labelPtrPtr;    /* Place to return label ptr. */
  69. {
  70.     Disk_Label        *labelPtr;
  71.     ReturnStatus    status = SUCCESS;
  72.     labelPtr = *labelPtrPtr;
  73.     if (labelPtr == NULL) {
  74.     labelPtr = Disk_ReadLabel(fid);
  75.     if (labelPtr != NULL) {
  76.         if ((labelType != DISK_NO_LABEL) && 
  77.             (labelType != labelPtr->labelType) && (!printOnly)) {
  78.         Disk_Label    *newLabelPtr;
  79.         status = Disk_EraseLabel(fid, labelPtr->labelType);
  80.         if (status != SUCCESS) {
  81.             printf("Couldn't erase old label.\n");
  82.             return status;
  83.         }
  84.         newLabelPtr = Disk_NewLabel(labelType);
  85.         newLabelPtr->numHeads = labelPtr->numHeads;
  86.         newLabelPtr->numSectors = labelPtr->numSectors;
  87.         newLabelPtr->numCylinders = labelPtr->numCylinders;
  88.         newLabelPtr->numAltCylinders = labelPtr->numAltCylinders;
  89.         bcopy(labelPtr->asciiLabel, newLabelPtr->asciiLabel, 
  90.             labelPtr->asciiLabelLen);
  91.         bcopy((char *) labelPtr->partitions, 
  92.               (char *) newLabelPtr->partitions,
  93.               sizeof(labelPtr->partitions));
  94.         labelPtr = newLabelPtr;
  95.         }
  96.     } else {
  97.         if (labelType == DISK_NO_LABEL) {
  98.         printf("Disk does not have a label. Use -labeltype\n");
  99.         return FAILURE;
  100.         }
  101.         labelPtr = Disk_NewLabel(labelType);
  102.         if (labelPtr == NULL) {
  103.         return FAILURE;
  104.         }
  105.     }
  106.     *labelPtrPtr = labelPtr;
  107.     }
  108.     if (disktab) {
  109.     status = ScanDisktab(disktabName, TRUE, diskType, labelPtr);
  110.     } else if (!scsiDisk) {
  111.     printf("You must specify the -configdisktab for a non-scsi disk.\n");
  112.     return FAILURE;
  113.     } else {
  114. #ifdef sprite
  115.     status = InventConfig(fid, labelPtr);
  116. #else
  117.     printf("You must use the -configdisktab option on unix.\n");
  118.     return FAILURE;
  119. #endif
  120.     }
  121.     if (status != SUCCESS) {
  122.     fprintf(stderr, "Unable to reconfigure disk\n");
  123.     } else {
  124.     int i;
  125.     /*
  126.      * Clear the partition map since we've changed the disk
  127.      * geometry.
  128.      */
  129.     for (i = 0; i < DISK_MAX_PARTS; i++) {
  130.         labelPtr->partitions[i].firstCylinder = 0;
  131.         labelPtr->partitions[i].numCylinders = 0;
  132.     }
  133.     }
  134.     return status;
  135. }
  136.  
  137. /*
  138.  *----------------------------------------------------------------------
  139.  *
  140.  * Repartition --
  141.  *
  142.  *    Repartitions the disk. If the disktab variable is TRUE then
  143.  *    all partitions are set from the disktab file, otherwise
  144.  *    a single partition is changed.
  145.  *
  146.  * Results:
  147.  *    SUCCESS if the partition map was changed properly, 
  148.  *    FAILURE otherwise
  149.  *
  150.  * Side effects:
  151.  *    The label on the disk is changed.
  152.  *
  153.  *----------------------------------------------------------------------
  154.  */
  155.  
  156. ReturnStatus
  157. Repartition(fid, disktab, disktabName, diskType, labelType, partition,
  158.     sizes, labelPtrPtr)
  159.     int            fid;        /* Handle for first partition of disk*/
  160.     Boolean        disktab;    /* TRUE => use disktab file. */
  161.     char        *disktabName;    /* Name of disktab file. */
  162.     char        *diskType;    /* Type of disk. */
  163.     Disk_NativeLabelType labelType;    /* Type of label to write. */
  164.     int            partition;    /* Which parition to change. */
  165.     int            *sizes;        /* Sizes of partitions as a pct.*/
  166.     Disk_Label        **labelPtrPtr;    /* Place to return label ptr. */
  167.  
  168. {
  169.    Disk_Label        *labelPtr = *labelPtrPtr;
  170.    ReturnStatus        status = SUCCESS;
  171.    int            adjust;
  172.  
  173.    if (labelPtr == NULL) {
  174.     labelPtr = Disk_ReadLabel(fid);
  175.     if (labelPtr != NULL) {
  176.         if ((labelType != DISK_NO_LABEL) && 
  177.             (labelType != labelPtr->labelType) && (!printOnly)) {
  178.         status = Disk_EraseLabel(fid, labelPtr->labelType);
  179.         if (status != SUCCESS) {
  180.             fprintf(stderr, "Can't erase disk label.\n");
  181.             return status;
  182.         }
  183.         labelPtr->labelType = labelType;
  184.         }
  185.     } else {
  186.         if (labelType == DISK_NO_LABEL) {
  187.         printf("Disk does not have a label. Use -labeltype\n");
  188.         return FAILURE;
  189.         }
  190.         labelPtr = Disk_NewLabel(labelType);
  191.         if (labelPtr == NULL) {
  192.         fprintf(stderr, "The disk does not have a label.\n");
  193.         return FAILURE;
  194.         }
  195.     }
  196.     *labelPtrPtr = labelPtr;
  197.     }
  198.     if (disktab) {
  199.     status = ScanDisktab(disktabName, FALSE, diskType, labelPtr);
  200.     } else {
  201.     int        firstCylinder;
  202.     int        numCylinders;
  203.     int        i;
  204.     Disk_Partition    *partitions = labelPtr->partitions;
  205.     for (i = 0; i < 7; i++) {
  206.         if (sizes[i] == 0) {
  207.         continue;
  208.         }
  209.         adjust = labelPtr->numCylinders * sizes[i] / 100;
  210.         /*
  211.          * Adjust the start and size of the current partition, and the
  212.          * start of all partitions that follow.
  213.          */
  214.         switch(i) {
  215.         case A_PART:
  216.             firstCylinder = 0;
  217.             partitions[B_PART].firstCylinder += adjust;
  218.             partitions[D_PART].firstCylinder += adjust;
  219.             partitions[E_PART].firstCylinder += adjust;
  220.             partitions[F_PART].firstCylinder += adjust;
  221.             partitions[G_PART].firstCylinder += adjust;
  222.             break;
  223.         case B_PART:
  224.             firstCylinder = partitions[A_PART].firstCylinder +
  225.                     partitions[A_PART].numCylinders;
  226.             partitions[D_PART].firstCylinder += adjust;
  227.             partitions[E_PART].firstCylinder += adjust;
  228.             partitions[F_PART].firstCylinder += adjust;
  229.             partitions[G_PART].firstCylinder += adjust;
  230.             break;
  231.         case C_PART:
  232.             firstCylinder = 0;
  233.             break;
  234.         case D_PART:
  235.             partitions[E_PART].firstCylinder += adjust;
  236.             partitions[F_PART].firstCylinder += adjust;
  237.         case G_PART:
  238.             firstCylinder = partitions[A_PART].firstCylinder +
  239.                     partitions[A_PART].numCylinders;
  240.             break;
  241.         case E_PART:
  242.             firstCylinder = partitions[D_PART].firstCylinder +
  243.                     partitions[D_PART].numCylinders;
  244.             partitions[F_PART].firstCylinder += adjust;
  245.             break;
  246.         case F_PART:
  247.             firstCylinder = partitions[E_PART].firstCylinder +
  248.                     partitions[E_PART].numCylinders;
  249.             break;
  250.         default:
  251.             fprintf(stderr, "Invalid partition %d\n", i);
  252.             return FAILURE;
  253.         }
  254.         partitions[i].firstCylinder = firstCylinder;
  255.         numCylinders = labelPtr->numCylinders * sizes[i] / 100;
  256.         partitions[i].numCylinders = numCylinders;
  257.     }
  258.     }
  259.     return status;
  260. }
  261.  
  262.  
  263. #define    BUF_SIZE    256
  264.  
  265. /*
  266.  *----------------------------------------------------------------------
  267.  *
  268.  * ScanDisktab --
  269.  *
  270.  *    Initialize the disk label by reading the information from
  271.  *     the disktab file.
  272.  *
  273.  * Results:
  274.  *    SUCCESS if the label was initialized properly, FAILURE otherwise
  275.  *
  276.  * Side effects:
  277.  *    None.
  278.  *
  279.  *----------------------------------------------------------------------
  280.  */
  281.  
  282. static ReturnStatus
  283. ScanDisktab(fileName, reconfig, diskType, labelPtr)
  284.     char    *fileName;    /* Name of the disktab file. */
  285.     Boolean    reconfig;    /* Reconfigure disk */
  286.     char    *diskType;    /* Type of disk. */
  287.     Disk_Label    *labelPtr;    /* The disk label. */
  288. {
  289.     char        buf[BUF_SIZE];
  290.     char        fullBuf[BUF_SIZE];
  291.     char        *bufPtr;
  292.     int            fullBufLen;
  293.     int            sectorsPerTrack;
  294.     int            tracksPerCylinder;
  295.     int            sectorsPerCylinder;
  296.     int            numCylinders;
  297.     FILE        *fp;
  298.     Disk_Partition      *partitions;
  299.     Disk_Partition      dummy[DISK_MAX_PARTS];
  300.     int            len;
  301.     int            i;
  302.  
  303.     if (diskType == NULL) {
  304.     printf(
  305.     "You must use the -disktype option when using the disktab file.\n");
  306.     return FAILURE;
  307.     }
  308.     fp = fopen(fileName, "r");
  309.     if (fp == NULL) {
  310.     fprintf(stderr,"Can't open %s", fileName);
  311.     exit(1);
  312.     }
  313.     len = strlen(diskType);
  314.     /*
  315.      * Scan until we reach a line that contains the disk type in it.
  316.      */
  317.     while (fgets(buf, BUF_SIZE, fp) != NULL) {
  318.     if (strncmp(diskType, buf, len) == 0 &&
  319.         buf[len] == '|') {
  320.         /*
  321.          * We found the disk type.
  322.          */
  323.         break;
  324.     }
  325.     }
  326.     if (strncmp(diskType, buf, len) != 0) {
  327.     fprintf(stderr, "`%s' not in disktab\n", diskType);
  328.     fprintf(stderr, "Note: type must be first entry on line\n");
  329.     return FAILURE;
  330.     }
  331.  
  332.     fullBufLen = 0;
  333.     /*
  334.      * Now cram all of the lines that end in "\" together.
  335.      */
  336.     while (1) {
  337.     for (bufPtr = buf; 
  338.          *bufPtr != '\n' && *bufPtr != '\\' && (bufPtr - buf < sizeof(buf));
  339.          bufPtr++) {
  340.         if (*bufPtr != ' ' && *bufPtr != '\t') {
  341.         if (fullBufLen == sizeof(fullBuf)) {
  342.             break;
  343.         }
  344.         fullBuf[fullBufLen] = *bufPtr;
  345.         fullBufLen++;
  346.         }
  347.     }
  348.     if (bufPtr - buf == sizeof(buf) || fullBufLen == sizeof(fullBuf)) {
  349.         printf("Buffer overflow.\n");
  350.         return FAILURE;
  351.     }
  352.     if (*bufPtr == '\n') {
  353.         fullBuf[fullBufLen] = 0;
  354.         break;
  355.     }
  356.     if (fgets(buf, BUF_SIZE, fp) == NULL) {
  357.         fprintf(stderr, "Premature EOF\n");
  358.         exit(1);
  359.     }
  360.     }
  361.     if (reconfig) {
  362.     partitions = dummy;
  363.     } else {
  364.     partitions = labelPtr->partitions;
  365.     }
  366.     /*
  367.      * Now build up a partition table.
  368.      */
  369.     for (i = 0; i < DISK_MAX_PARTS; i++) {
  370.     partitions[i].firstCylinder = 0;
  371.     partitions[i].numCylinders = 0;
  372.     }
  373.     for (bufPtr = fullBuf; *bufPtr != 0; bufPtr++) {
  374.     int    partition;
  375.  
  376.     if (strncmp(bufPtr, ":ns#", 4) == 0) {
  377.         bufPtr += 4;
  378.         sscanf(bufPtr, "%d", §orsPerTrack);
  379.     } else if (strncmp(bufPtr, ":nt#", 4) == 0) {
  380.         bufPtr += 4;
  381.         sscanf(bufPtr, "%d", &tracksPerCylinder);
  382.     } else if (strncmp(bufPtr, ":nc#", 4) == 0) {
  383.         bufPtr += 4;
  384.         sscanf(bufPtr, "%d", &numCylinders);
  385.     } else if (strncmp(bufPtr, ":p", 2) == 0) {
  386.         /*
  387.          * Skip past the ":p".
  388.          */
  389.         bufPtr += 2;
  390.         partition = *bufPtr - 'a';
  391.         /*
  392.          * Skip past the partition character and the #.
  393.          */
  394.         bufPtr += 2;
  395.         sscanf(bufPtr, "%d", &partitions[partition].numCylinders);
  396.     }
  397.     }
  398.     if (reconfig) {
  399.     strcpy(labelPtr->asciiLabel, diskType);
  400.     labelPtr->numHeads = tracksPerCylinder;
  401.     labelPtr->numSectors = sectorsPerTrack;
  402.     labelPtr->numCylinders = numCylinders;
  403.     return SUCCESS;
  404.     } else {
  405.     tracksPerCylinder = labelPtr->numHeads;
  406.     sectorsPerTrack = labelPtr->numSectors;
  407.     numCylinders = labelPtr->numCylinders;
  408.     }
  409.     /*
  410.      * The partition sizes in the disktab file are in terms of sectors.
  411.      * Convert this to cylinders.
  412.      */
  413.     sectorsPerCylinder = sectorsPerTrack * tracksPerCylinder;
  414.     for (i = 0; i < FSDM_NUM_DISK_PARTS; i++) {
  415.     partitions[i].numCylinders /= sectorsPerCylinder;
  416.     }
  417.     /*
  418.      * Now that we've built up the number of cylinders build up the
  419.      * cylinder offsets.
  420.      */
  421.     partitions[A_PART].firstCylinder = 0;
  422.     partitions[B_PART].firstCylinder = partitions[A_PART].numCylinders;
  423.     partitions[C_PART].firstCylinder = 0;
  424.     partitions[D_PART].firstCylinder = partitions[B_PART].firstCylinder + 
  425.             partitions[B_PART].numCylinders;
  426.     partitions[E_PART].firstCylinder = partitions[D_PART].firstCylinder + 
  427.             partitions[D_PART].numCylinders;
  428.     partitions[F_PART].firstCylinder = partitions[E_PART].firstCylinder + 
  429.             partitions[E_PART].numCylinders;
  430.     partitions[F_PART].numCylinders = 
  431.             numCylinders - (partitions[E_PART].firstCylinder +
  432.                     partitions[E_PART].numCylinders);
  433.     partitions[G_PART].firstCylinder = partitions[B_PART].firstCylinder + 
  434.             partitions[B_PART].numCylinders;
  435.     partitions[G_PART].numCylinders = 
  436.             numCylinders - (partitions[B_PART].firstCylinder +
  437.                     partitions[B_PART].numCylinders);
  438.  
  439.     return SUCCESS;
  440. }
  441.  
  442. /*
  443.  *----------------------------------------------------------------------
  444.  *
  445.  * InventConfig --
  446.  *
  447.  *    Invents a configuration for the disk that maximizes the
  448.  *    amount of available space.  This only works if the disk
  449.  *    is a scsi disk.
  450.  *
  451.  * Results:
  452.  *    Pointer to the label.
  453.  *
  454.  * Side effects:
  455.  *    A scsi command is sent to the disk.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459.  
  460. #ifdef sprite 
  461. ReturnStatus
  462. InventConfig(fid, labelPtr)
  463.     int        fid;        /* Handle on the raw disk. */
  464.     Disk_Label    *labelPtr;    /* The disk label. */
  465. {
  466.     ScsiCmd        cmd;        
  467.     CmdStatus        cmdStatus;
  468.     struct stat     statbuf;
  469.     int            numSectors;
  470.     int            size;
  471.     ReturnStatus    status = SUCCESS;
  472.     int            sectorsPerBlock;
  473.     int            lowerLimit;
  474.     int            upperLimit;
  475.     int            best;
  476.     int            leastWasted;
  477.     int            i;
  478.  
  479.     /*
  480.      * Send a Read Capacity SCSI command to the disk to find out how many
  481.      * sectors there are and how many bytes per sector.
  482.      */
  483.     bzero((char *) &cmd, sizeof(cmd));;
  484.     cmd.hdr.bufferLen = sizeof(ReadCapacityCommand);
  485.     cmd.hdr.commandLen = sizeof(ReadCapacityCommand);
  486.     cmd.hdr.dataOffset = sizeof(Dev_ScsiCommand)+sizeof(ReadCapacityCommand);
  487.     cmd.cmd.command = 0x25;
  488.     fstat(fid, &statbuf);
  489.     cmd.cmd.lun = (statbuf.st_rdev >> 7) & 0x7;
  490.     cmd.cmd.pmi = 0;
  491.     status = Fs_IOControl(fid, IOC_SCSI_COMMAND, cmd.hdr.dataOffset,
  492.             (char *) &cmd, sizeof(CmdStatus), (char *) &cmdStatus);
  493.     if (status != 0) {
  494.     fprintf(stderr,"Fs_IoControl returned status 0x%x : %s\n",status,
  495.             Stat_GetMsg(status));
  496.     exit(1);
  497.     }
  498.     numSectors = ((unsigned int)cmdStatus.info.result.addr3 << 24 | 
  499.         (unsigned int)cmdStatus.info.result.addr2 << 16 |
  500.         (unsigned int)cmdStatus.info.result.addr1 << 8 |
  501.         (unsigned int)cmdStatus.info.result.addr0) + 1;
  502.     size = (unsigned int)cmdStatus.info.result.size3 << 24 | 
  503.         (unsigned int)cmdStatus.info.result.size2 << 16 |
  504.         (unsigned int)cmdStatus.info.result.size1 << 8 |
  505.         (unsigned int)cmdStatus.info.result.size0;
  506.     if (size != 512) {
  507.     fprintf(stderr, "Whoa!  There are %d bytes in a sector!!!\n", size);
  508.     return FAILURE;
  509.     }
  510.     /*
  511.      * Now compute a "good" number of sectors per cylinder so that
  512.      * we waste as few as possible.  Remember that file system blocks
  513.      * cannot cross cylinder boundaries, and that the file system uses
  514.      * cylinders to localize the allocation of files. Therefore we
  515.      * don't want cylinders to be too big or too small. 
  516.      * I've arbitrarily
  517.      * chosen a lower limit of 16 blocks (64 K) and 
  518.      * picked an upper limit of 256 blocks (1 Mb).
  519.      * We also don't want too many cylinders since the filesystem
  520.      * does stuff on a cylinder basis.  The upper limit on the
  521.      * number of cylinders is 3000.
  522.      *
  523.      * The computation is brute force.  I don't know of a closed form
  524.      * solution.
  525.      */
  526.     sectorsPerBlock = FS_BLOCK_SIZE / size;
  527.     lowerLimit = sectorsPerBlock * 16;
  528.     upperLimit = sectorsPerBlock * 256;
  529.     if (numSectors / lowerLimit > 3000) {
  530.     lowerLimit = numSectors / 3000;
  531.     if (lowerLimit % sectorsPerBlock != 0) {
  532.         lowerLimit += sectorsPerBlock - (lowerLimit % sectorsPerBlock);
  533.     }
  534.     }
  535.     best = 0;
  536.     leastWasted = upperLimit;
  537.     /*
  538.      * Iterate over all sizes of cylinders such that a whole number
  539.      * of blocks fit in a cylinder.
  540.      */
  541.     for (i = lowerLimit; i <= upperLimit; i+=sectorsPerBlock) {
  542.     int left;
  543.  
  544.     /*
  545.      * Compute number of leftover sectors because the disk size
  546.      * is not a multiple of the cylinder size, and due to the
  547.      * one cylinder that we'll throw away at the start of the disk
  548.      * for the boot sectors and stuff.
  549.      */
  550.     left = numSectors % i + i;
  551.     if (left < leastWasted) {
  552.         leastWasted = left;
  553.         best = i;
  554.     }
  555.     }
  556.     labelPtr->numHeads = 1;
  557.     labelPtr->numSectors = best;
  558.     labelPtr->numCylinders = numSectors / best;
  559.     return status;
  560. }
  561. #endif
  562.  
  563.  
  564. /*
  565.  *----------------------------------------------------------------------
  566.  *
  567.  * ConfirmDiskSize --
  568.  *
  569.  *    Checks that the the last sector of the disk as computed from
  570.  *    the information in the label actually exists.
  571.  *
  572.  * Results:
  573.  *    SUCCESS if the sector can be read, FAILURE otherwise
  574.  *
  575.  * Side effects:
  576.  *    A sector is read from the disk.
  577.  *
  578.  *----------------------------------------------------------------------
  579.  */
  580.  
  581. ReturnStatus
  582. ConfirmDiskSize(fid, labelPtr, sizes)
  583.     int        fid;        /* Handle on the raw disk. */
  584.     Disk_Label    *labelPtr;    /* The disk label. */
  585.     int        *sizes;        /* Size of partitions. */
  586. {
  587.     int         lastSector;
  588.     int            status;
  589.     static char        buffer[DEV_BYTES_PER_SECTOR];
  590.     ReturnStatus    returnStatus = SUCCESS;
  591.     int            i;
  592.  
  593.     lastSector = labelPtr->numCylinders * labelPtr->numHeads *
  594.             labelPtr->numSectors - 1;
  595.     status = Disk_SectorRead(fid, lastSector, 1, buffer);
  596.     if (status != 0) {
  597.     fprintf(stderr, "Can't read last sector (%d) of disk.\n", lastSector);
  598.     fprintf(stderr, "Disk reconfiguration/repartition failed.\n");
  599.     return FAILURE;
  600.     }
  601.     for (i = 0; i < 7; i++) {
  602.     /*
  603.      * Ignore partitions we haven't modified.
  604.      */
  605.     if (sizes[i] == 0) {
  606.         continue;
  607.     }
  608.     lastSector = (labelPtr->partitions[i].firstCylinder  +
  609.              labelPtr->partitions[i].numCylinders) *
  610.              labelPtr->numHeads * labelPtr->numSectors - 1;
  611.     if (lastSector > 0) {
  612.         status = Disk_SectorRead(fid, lastSector, 1, buffer);
  613.         if (status != 0) {
  614.         fprintf(stderr, 
  615.             "Can't read last sector (%d) of the '%c' partition\n", 
  616.             lastSector, ((char) i) + 'a');
  617.         returnStatus = FAILURE;
  618.         }
  619.     }
  620.     }
  621.     return returnStatus;
  622. }
  623.  
  624.